21-5 优化代码创建基于casl的策略权限控制服务
权限控制服务架构设计
策略处理类型抽象
1. JSON类型(通用权限场景)
适用场景:标准的CRUD权限控制,如用户管理、订单管理等基础业务场景
数据格式:
{
"action": "read",
"subject": "Article",
"fields": ["title", "content"],
"conditions": { "status": "published" }
}
typescript
实现原理:
- 直接解析JSON格式的策略规则
- 通过CASL的
can/cannot
方法建立权限映射 - 支持字段级细粒度控制(fields)
典型应用:
- 前端组件权限渲染控制
- API接口访问权限校验
- 数据表格字段可见性管理
2. Mongo类型(查询条件场景)
适用场景:MongoDB数据库查询时的数据过滤
特殊能力:
- 自动将权限条件转换为MongoDB查询语法
- 支持
$and
/$or
等复杂查询操作符 - 动态注入查询条件到Mongoose查询链
实现示例:
// 权限策略
{
"type": 1,
"action": "read",
"subject": "User",
"conditions": { "department": "IT" }
}
// 生成的Mongo查询
User.find().accessibleBy(ability);
// 自动添加条件: { department: "IT" }
typescript
3. Function类型(动态逻辑场景)
适用场景:
- 需要运行时计算的复杂权限逻辑
- 多因素组合的权限判断(如:时间+地点+角色)
- 调用外部服务的权限验证
安全实践:
// 使用沙箱执行动态函数
import { VM } from 'vm2';
const vm = new VM({ sandbox: {} });
const safeEval = (code: string) => {
try {
return vm.run(code);
} catch (e) {
throw new Error(`权限函数执行错误: ${e.message}`);
}
}
typescript
IPolicy策略接口深度解析
核心字段说明
字段 | 类型 | 必填 | 说明 |
---|---|---|---|
type | 0|1|2 | 是 | 策略处理器路由标识 |
effect | "can"|"cannot" | 是 | 权限白名单/黑名单模式 |
action | string | 是 | 支持通配符如"manage" |
subject | string | 是 | 支持继承关系"Post:own" |
fields | string | 否 | 支持嵌套字段"profile.address" |
conditions | object|string | 否 | 支持JSON序列化 |
args | any | 否 | 函数参数动态注入 |
类型安全增强方案
// 使用模板字面量类型约束action/subject
type ActionType = 'create' | 'read' | 'update' | 'delete' | 'manage';
type SubjectType = `User${':own' | ''}` | `Post${':own' | ''}`;
interface EnhancedPolicy extends Omit<IPolicy, 'action' | 'subject'> {
action: ActionType;
subject: SubjectType;
}
typescript
条件表达式进阶用法
// 支持多条件组合
conditions: {
$or: [
{ authorId: user.id },
{ status: 'public', publishAt: { $lt: Date.now() } }
]
}
// 支持函数式条件(CASL v6+)
conditions: (item: any) => item.owner === user.id
typescript
架构设计图
常见问题解答
Q1 如何实现跨策略的条件共享?
A: 使用条件工厂函数:
const commonConditions = {
tenantId: (user) => user.tenantId
};
// 策略中引用
conditions: {
...commonConditions,
status: 'active'
}
typescript
Q2 字段权限如何实现继承?
A: 通过subject
命名约定:
// 父策略
{ subject: "Document", fields: ["title"] }
// 子策略自动继承
{ subject: "Article" } // 默认拥有title字段权限
typescript
Q3 如何调试动态函数策略?
A: 推荐方案:
- 在开发环境禁用函数编译缓存
- 添加策略版本号标识
- 使用source-map支持错误定位
延伸学习资源
- CASL官方文档 - 最新v6特性详解
- Mongoose集成指南 - 数据库级权限控制
- Vue权限组件案例 - 前端实现参考
- 策略性能优化 - 百万级策略处理方案
Ability构建核心逻辑扩展
能力类型深度解析
MongoAbility 特有能力
interface MongoAbility extends PureAbility {
// MongoDB特有方法
toMongoQuery(subject: Subject): Query | null;
accessibleBy<T extends Document>(model: Model<T>): QueryWithHelpers<T, T>;
// 增强的查询条件处理
private _conditionsMatcher: ConditionsMatcher;
}
typescript
典型应用场景:
- 自动生成安全的MongoDB查询条件
- 与Mongoose模型直接集成
- 复杂聚合查询的权限过滤
AppAbility 核心扩展
interface AppAbility extends PureAbility {
// 高级条件匹配能力
matchConditions(
subject: Subject,
conditions: Conditions
): boolean;
// 动态策略注入
updatePolicy(policy: IPolicy): void;
}
typescript
优势:
- 支持运行时策略热更新
- 实现基于内存的高效条件匹配
- 可扩展自定义匹配逻辑
工厂函数增强实现
带缓存的优化版本
const abilityCache = new WeakMap<IPolicy[], AbilityType[]>();
function buildAbility(policies: IPolicy[], useCache = true): AbilityType[] {
if (useCache && abilityCache.has(policies)) {
return abilityCache.get(policies)!;
}
const abilityArr = policies.map(policy => {
try {
const handler = handlers[policy.type] || handleJsonType;
return handler(policy);
} catch (e) {
console.error(`策略处理失败: ${policy.action}@${policy.subject}`, e);
return createEmptyAbility(); // 降级处理
}
});
if (useCache) {
abilityCache.set(policies, abilityArr);
}
return abilityArr;
}
const handlers = {
0: handleJsonType,
1: handleMongoType,
2: handleFunctionType
};
typescript
性能优化技巧
- 策略预处理:
// 提前标准化策略格式
function normalizePolicies(policies: IPolicy[]) {
return policies.map(p => ({
...p,
conditions: typeof p.conditions === 'string' ?
JSON.parse(p.conditions) : p.conditions
}));
}
typescript
- 并行处理(Node.js环境):
import { Worker } from 'worker_threads';
async function parallelBuild(policies: IPolicy[]) {
const chunkSize = Math.ceil(policies.length / 4);
const chunks = Array.from({ length: 4 }, (_, i) =>
policies.slice(i * chunkSize, (i + 1) * chunkSize)
);
return (await Promise.all(
chunks.map(chunk =>
new Promise<AbilityType[]>(resolve => {
const worker = new Worker('./ability-builder.js', {
workerData: chunk
});
worker.on('message', resolve);
})
)
)).flat();
}
typescript
错误处理机制
自定义错误类型
class AbilityBuildError extends Error {
constructor(
public policy: IPolicy,
public originalError: Error
) {
super(`策略构建失败: ${policy.action}@${policy.subject}`);
}
get details() {
return {
type: this.policy.type,
conditions: this.policy.conditions,
stack: this.originalError.stack
};
}
}
typescript
错误边界处理
function safeBuild(policy: IPolicy): AbilityType {
try {
const handler = {
0: handleJsonType,
1: handleMongoType,
2: handleFunctionType
}[policy.type];
return handler(policy);
} catch (e) {
if (policy.type === 2) {
// 函数策略失败时降级为静态检查
return handleJsonType({
...policy,
type: 0,
conditions: { $fallback: true }
});
}
throw new AbilityBuildError(policy, e);
}
}
typescript
类型安全进阶
使用泛型增强
function buildAbility<T extends AbilityType>(
policies: IPolicy[],
abilityClass: new () => T
): T[] {
return policies.map(policy => {
const ability = new abilityClass();
const handler = getHandler(policy.type);
return handler(policy, ability);
});
}
// 使用示例
const mongoAbilities = buildAbility(policies, MongoAbility);
typescript
条件类型推导
type AbilityForPolicy<T extends IPolicy> =
T['type'] extends 0 ? AppAbility :
T['type'] extends 1 ? MongoAbility :
T['type'] extends 2 ? PureAbility :
never;
function buildTypedAbility<T extends IPolicy>(
policy: T
): AbilityForPolicy<T> {
// ...实现逻辑
}
typescript
生命周期扩展
最佳实践建议
- 生产环境配置:
// 启用缓存和性能监控
const abilities = buildAbility(policies, {
cacheTTL: 3600, // 1小时缓存
metrics: true // 收集性能指标
});
typescript
- 调试模式:
// 开发环境详细日志
function debugBuild(policies: IPolicy[]) {
return buildAbility(policies, {
debug: true,
onPolicyProcess: (policy, time) => {
console.log(`[Ability] 处理策略 ${policy.action}@${policy.subject}`,
`耗时 ${time}ms`);
}
});
}
typescript
- 微服务集成:
// 远程策略加载
async function loadRemotePolicies(userId: string) {
const res = await fetch(`/api/policies/${userId}`);
return normalizePolicies(await res.json());
}
// 组合使用
const userPolicies = await loadRemotePolicies(currentUser.id);
const abilities = buildAbility(userPolicies);
typescript
扩展思考题
- 如何实现策略的版本控制,支持灰度发布?
- 在Serverless环境下如何优化冷启动时的策略构建性能?
- 如何设计跨微服务的统一权限能力共享机制?
JSON类型策略实现深度扩展
权限方向选择器增强版
1. 支持多级权限控制
const determineAction = (
effect: string,
builder: AbilityBuilder,
options?: {
strictMode?: boolean; // 严格模式禁止权限穿透
hierarchy?: string[]; // 权限继承层级
}
) => {
const baseAction = effect === "can" ? builder.can : builder.cannot;
return (action: string, subject: Subject, fields?: string[], conditions?: Conditions) => {
// 处理权限继承
if (options?.hierarchy) {
options.hierarchy.forEach(level => {
baseAction(action, `${subject}:${level}`, fields, conditions);
});
}
// 基础权限设置
const result = baseAction(action, subject, fields, conditions);
// 严格模式处理
if (options?.strictMode) {
builder.cannot('manage', 'all'); // 默认禁止所有未明确声明的权限
}
return result;
};
};
typescript
2. 带权限缓存的优化版本
const actionCache = new WeakMap<AbilityBuilder, Map<string, Function>>();
function cachedDetermineAction(effect: string, builder: AbilityBuilder) {
if (!actionCache.has(builder)) {
actionCache.set(builder, new Map());
}
const cache = actionCache.get(builder)!;
const cacheKey = `${effect}:${builder.constructor.name}`;
if (!cache.has(cacheKey)) {
cache.set(cacheKey, effect === "can" ? builder.can : builder.cannot);
}
return cache.get(cacheKey)!;
}
typescript
条件解析与构建进阶实现
1. 安全条件解析器
import { safeLoad } from 'js-yaml';
function parseConditions(conditions: string | object): Conditions {
if (typeof conditions !== 'string') return conditions || {};
try {
// 支持JSON和YAML两种格式
if (conditions.trim().startsWith('{')) {
return JSON.parse(conditions);
}
return safeLoad(conditions) as Conditions;
} catch (e) {
console.warn(`条件解析失败,使用空条件: ${e.message}`);
return {};
}
}
typescript
2. 带条件验证的构建器
function handleJsonType(
policy: IPolicy,
options?: {
validate?: (conditions: Conditions) => boolean;
transform?: (conditions: Conditions) => Conditions;
}
) {
const builder = new AbilityBuilder(createMongoAbility);
const action = determineAction(policy.effect, builder);
// 条件解析与转换
let conditions = parseConditions(policy.conditions);
if (options?.transform) {
conditions = options.transform(conditions);
}
// 条件验证
if (options?.validate && !options.validate(conditions)) {
throw new Error(`无效的条件格式: ${JSON.stringify(conditions)}`);
}
// 字段权限处理
const fields = policy.fields?.split(',')?.map(f => f.trim());
// 构建权限规则
action(policy.action, policy.subject, fields, conditions);
return {
ability: builder.build(),
meta: {
originalConditions: policy.conditions,
normalizedConditions: conditions
}
};
}
typescript
高级应用场景
1. 动态字段权限控制
function handleDynamicFields(policy: IPolicy, context: any) {
const builder = new AbilityBuilder(createMongoAbility);
const action = determineAction(policy.effect, builder);
// 解析带模板的字段权限
const resolveFields = () => {
if (!policy.fields) return undefined;
return policy.fields
.replace(/\${(.*?)}/g, (_, key) => context[key] || '')
.split(',')
.map(f => f.trim());
};
action(
policy.action,
policy.subject,
resolveFields(),
parseConditions(policy.conditions)
);
return builder.build();
}
typescript
2. 多条件组合策略
function handleCompositePolicy(
policies: IPolicy[],
mergeStrategy: 'AND' | 'OR' = 'AND'
) {
const builder = new AbilityBuilder(createMongoAbility);
policies.forEach(policy => {
const action = determineAction(policy.effect, builder);
const conditions = parseConditions(policy.conditions);
if (mergeStrategy === 'AND') {
action(policy.action, policy.subject, policy.fields?.split(','), {
$and: [conditions]
});
} else {
action(policy.action, policy.subject, policy.fields?.split(','), {
$or: [conditions]
});
}
});
return builder.build();
}
typescript
错误处理与调试
1. 详细的错误日志
function debugHandleJsonType(policy: IPolicy) {
try {
console.time('PolicyBuild');
const result = handleJsonType(policy);
console.log(`策略构建成功: ${policy.action}@${policy.subject}`, {
fields: policy.fields,
conditions: policy.conditions
});
return result;
} catch (e) {
console.error(`策略构建失败: ${policy.action}@${policy.subject}`, {
error: e.stack,
policy
});
throw e;
} finally {
console.timeEnd('PolicyBuild');
}
}
typescript
2. 可视化策略分析
性能优化方案
- 条件预编译:
const conditionCache = new Map<string, Conditions>();
function getCachedConditions(raw: string | object): Conditions {
const key = typeof raw === 'string' ? raw : JSON.stringify(raw);
if (!conditionCache.has(key)) {
conditionCache.set(key, parseConditions(raw));
}
return conditionCache.get(key)!;
}
typescript
- 批量策略处理:
function batchHandleJsonType(policies: IPolicy[]) {
const builder = new AbilityBuilder(createMongoAbility);
const actionMap = new Map<string, Function>();
policies.forEach(policy => {
if (!actionMap.has(policy.effect)) {
actionMap.set(policy.effect, determineAction(policy.effect, builder));
}
const action = actionMap.get(policy.effect)!;
action(
policy.action,
policy.subject,
policy.fields?.split(','),
getCachedConditions(policy.conditions)
);
});
return builder.build();
}
typescript
单元测试建议
describe('JSON策略处理器', () => {
it('应正确解析字符串条件', () => {
const policy = {
type: 0,
effect: 'can',
action: 'read',
subject: 'Article',
conditions: '{"status":"published"}'
};
const ability = handleJsonType(policy);
expect(ability.can('read', 'Article')).toBe(true);
});
it('应处理字段权限过滤', () => {
const policy = {
type: 0,
effect: 'can',
action: 'read',
subject: 'User',
fields: 'email,name'
};
const ability = handleJsonType(policy);
expect(ability.can('read', 'User', 'email')).toBe(true);
expect(ability.can('read', 'User', 'password')).toBe(false);
});
});
typescript
Mongo类型策略实现深度扩展
条件匹配器高级配置
1. 自定义解释器实现
const customInterpreters = {
// 实现部门数据隔离
department: (value: string) => ({
$or: [
{ 'department.id': value },
{ 'parentDepartments': { $in: [value] } }
]
}),
// 处理时间范围条件
timeRange: (value: { start: Date; end: Date }) => ({
createdAt: { $gte: value.start, $lte: value.end }
})
};
const enhancedMatcher = buildMongoQueryMatcher(
allPassingInterpreters,
{ ...allInterpreters, ...customInterpreters }
);
typescript
2. 多条件组合策略
function buildCompositeMatcher(
baseMatcher: ConditionsMatcher,
additionalConditions: Record<string, any>
) {
return (conditions: Record<string, any>) => {
const baseQuery = baseMatcher(conditions);
return { $and: [baseQuery, additionalConditions] };
};
}
// 使用示例
const withTenantFilter = buildCompositeMatcher(enhancedMatcher, {
tenantId: currentUser.tenantId
});
typescript
安全增强实现
1. 查询注入防护
import { sanitize } from 'mongo-sanitize';
function safeHandleMongoType(policy: IPolicy) {
const builder = new AbilityBuilder(createMongoAbility);
// 消毒处理条件对象
const sanitizedConditions = typeof policy.conditions === 'string'
? sanitize(JSON.parse(policy.conditions || '{}'))
: sanitize(policy.conditions || {});
const action = determineAction(policy.effect, builder);
const conditionsMatcher = buildMongoQueryMatcher(
allPassingInterpreters,
allInterpreters
);
action(policy.action, policy.subject, () =>
conditionsMatcher(sanitizedConditions)
);
return builder.build({ conditionsMatcher });
}
typescript
2. 深度查询限制
const depthLimitedMatcher = (maxDepth = 3) => {
const baseMatcher = buildMongoQueryMatcher(
allPassingInterpreters,
allInterpreters
);
return (conditions: any) => {
const checkDepth = (obj: any, depth = 0): any => {
if (depth > maxDepth) throw new Error(`查询深度超过限制: ${maxDepth}`);
return Object.entries(obj).reduce((acc, [key, value]) => {
if (typeof value === 'object' && value !== null) {
acc[key] = checkDepth(value, depth + 1);
} else {
acc[key] = value;
}
return acc;
}, {} as any);
};
return baseMatcher(checkDepth(conditions));
};
};
typescript
性能优化方案
1. 条件匹配器缓存
const matcherCache = new WeakMap<typeof allInterpreters, ConditionsMatcher>();
function getCachedMatcher(interpreters = allInterpreters) {
if (!matcherCache.has(interpreters)) {
matcherCache.set(interpreters,
buildMongoQueryMatcher(allPassingInterpreters, interpreters)
);
}
return matcherCache.get(interpreters)!;
}
typescript
2. 批量策略处理
function batchHandleMongoType(policies: IPolicy[]) {
const builder = new AbilityBuilder(createMongoAbility);
const matcher = getCachedMatcher();
policies.forEach(policy => {
const action = determineAction(policy.effect, builder);
action(policy.action, policy.subject, () =>
matcher(parseConditions(policy.conditions))
);
});
return {
ability: builder.build({ conditionsMatcher: matcher }),
stats: {
processed: policies.length,
cacheHit: matcherCache.size > 0
}
};
}
typescript
与Mongoose深度集成
1. 插件式集成
import { accessibleRecordsPlugin } from '@casl/mongoose';
// 初始化Mongoose插件
mongoose.plugin(accessibleRecordsPlugin, {
modelName: (model: any) => model.modelName
});
// 在Schema中定义权限字段
const ArticleSchema = new mongoose.Schema({
title: String,
status: { type: String, enum: ['draft', 'published'] },
permissions: {
viewGroups: [String],
editUsers: [mongoose.Schema.Types.ObjectId]
}
});
// 查询时自动应用权限
const visibleArticles = await Article.accessibleBy(ability)
.where('createdAt').gte(lastWeek);
typescript
2. 虚拟字段权限控制
UserSchema.virtual('accessibleProfile').get(function() {
return ability.filter('read', 'UserProfile', this.profile);
});
// 使用示例
const user = await User.findById(userId)
.select('+accessibleProfile')
.exec();
typescript
监控与调试
1. 查询日志记录
function createLoggedMatcher(baseMatcher: ConditionsMatcher) {
return (conditions: any) => {
console.log('[CASL-Mongo] 原始条件:', conditions);
const start = Date.now();
const query = baseMatcher(conditions);
console.log(`[CASL-Mongo] 生成查询 (${Date.now() - start}ms):`, query);
return query;
};
}
typescript
2. 性能指标收集
const matcherMetrics = {
totalCalls: 0,
totalTime: 0,
get avgTime() {
return this.totalCalls ? this.totalTime / this.totalCalls : 0;
}
};
const monitoredMatcher = (conditions: any) => {
const start = performance.now();
const result = enhancedMatcher(conditions);
const duration = performance.now() - start;
matcherMetrics.totalCalls++;
matcherMetrics.totalTime += duration;
return result;
};
typescript
测试策略建议
describe('Mongo策略处理器', () => {
let ability: MongoAbility;
beforeAll(() => {
const policy = {
type: 1,
effect: 'can',
action: 'read',
subject: 'Report',
conditions: { department: 'finance' }
};
ability = handleMongoType(policy);
});
it('应生成正确的Mongo查询条件', () => {
const query = ability.toMongoQuery('Report');
expect(query).toEqual({ department: 'finance' });
});
it('应与Mongoose模型正确集成', async () => {
const reports = await Report.accessibleBy(ability).exec();
reports.forEach(report => {
expect(report.department).toBe('finance');
});
});
});
typescript
扩展应用场景
1. 多租户数据隔离
function createTenantAwareMatcher(tenantId: string) {
const baseMatcher = getCachedMatcher();
return (conditions: any) => {
const originalQuery = baseMatcher(conditions);
return {
$and: [
originalQuery,
{ tenantId }
]
};
};
}
typescript
2. 动态字段投影
function createFieldProjector(fields: string[]) {
return {
project: fields.reduce((acc, field) => {
acc[field] = 1;
return acc;
}, {} as Record<string, 1>)
};
}
// 使用示例
const reports = await Report.accessibleBy(ability)
.find({}, createFieldProjector(['title', 'createdAt']))
.exec();
typescript
架构示意图
通过以上扩展,Mongo类型策略实现可以支持更复杂的业务场景,同时保证良好的性能和安全性。建议结合具体业务需求选择合适的扩展方案。
函数类型策略实现深度扩展
动态函数构造增强版
1. 支持异步函数策略
async function handleAsyncFunctionType(policy: IPolicy, context: any) {
const builder = new AbilityBuilder(createMongoAbility);
const action = determineAction(policy.effect, builder);
const dynamicFn = createSafeFunction(
policy.conditions as string,
policy.args || []
);
// 支持异步条件判断
const result = await dynamicFn(context);
action(policy.action, policy.subject, result);
return builder.build();
}
typescript
2. 带类型签名的函数工厂
type PolicyFunction<T = any> = (...args: any[]) => T | Promise<T>;
function createTypedFunction<T>(
code: string,
argNames: string[],
returnTypeGuard?: (val: any) => val is T
): PolicyFunction<T> {
const fn = new Function(...argNames, `return ${code}`) as PolicyFunction;
return (...args: any[]) => {
const result = fn(...args);
if (returnTypeGuard && !returnTypeGuard(result)) {
throw new Error(`函数返回类型不符合预期`);
}
return result;
};
}
typescript
安全增强实现
1. 沙箱执行环境
import { VM } from 'vm2';
const policyVM = new VM({
timeout: 100,
sandbox: {
// 允许使用的安全工具
_: require('lodash'),
moment: require('moment'),
// 业务上下文会被动态注入
},
eval: false // 禁用eval
});
function createSandboxedFunction(code: string, args: string[] = []) {
const wrappedCode = `(function(${args.join(',')}) {
try {
return ${code};
} catch(e) {
return { error: e.message };
}
}`;
return (context: object) => {
return policyVM.run(wrappedCode)(...Object.values(context));
};
}
typescript
2. 参数消毒处理
import DOMPurify from 'dompurify';
import { sanitize } from 'mongo-sanitize';
function sanitizePolicyArgs(args: any) {
if (typeof args === 'string') {
return DOMPurify.sanitize(args);
}
if (Array.isArray(args)) {
return args.map(arg => sanitize(arg));
}
return sanitize(args);
}
typescript
性能优化方案
1. 函数编译缓存
const functionCache = new Map<string, Function>();
function getCachedFunction(
code: string,
args: string[],
builderFn: (code: string, args: string[]) => Function
) {
const cacheKey = `${code}-${args.join(',')}`;
if (!functionCache.has(cacheKey)) {
functionCache.set(cacheKey, builderFn(code, args));
}
return functionCache.get(cacheKey)!;
}
typescript
2. 预编译策略包
function createPolicyBundle(policies: IPolicy[]) {
return policies
.filter(p => p.type === 2)
.map(policy => ({
name: `${policy.action}_${policy.subject}`,
execute: getCachedFunction(
policy.conditions as string,
Array.isArray(policy.args) ? policy.args : [],
createSandboxedFunction
)
}));
}
typescript
与CASL v6集成
1. 使用defineAbility
import { defineAbility } from '@casl/ability';
function createV6FunctionAbility(policy: IPolicy) {
return defineAbility((can, cannot) => {
const action = policy.effect === 'can' ? can : cannot;
const dynamicCheck = createSafeFunction(
policy.conditions as string,
policy.args || []
);
action(policy.action, policy.subject, (subject: any) =>
dynamicCheck(subject)
);
});
}
typescript
2. 自定义subject检测
class FunctionAbility extends PureAbility {
detectSubjectType(subject: any) {
if (typeof subject?.getPolicySubject === 'function') {
return subject.getPolicySubject();
}
return super.detectSubjectType(subject);
}
}
const ability = new FunctionAbility(
defineAbility((can) => {
can('read', 'Article', article =>
article.status === 'published'
);
})
);
typescript
监控与调试
1. 函数执行追踪
function createTracedFunction(fn: Function, policyId: string) {
return (...args: any[]) => {
console.time(`policy-${policyId}`);
try {
const result = fn(...args);
console.log(`策略${policyId}执行成功`, { args, result });
return result;
} catch (e) {
console.error(`策略${policyId}执行失败`, { args, error: e });
throw e;
} finally {
console.timeEnd(`policy-${policyId}`);
}
};
}
typescript
2. 性能指标收集
const policyMetrics = new Map<string, {
calls: number;
totalTime: number;
lastError?: string;
}>();
function monitoredFunction(fn: Function, policyName: string) {
return (...args: any[]) => {
const start = performance.now();
try {
const result = fn(...args);
const metrics = policyMetrics.get(policyName) || { calls: 0, totalTime: 0 };
metrics.calls++;
metrics.totalTime += performance.now() - start;
policyMetrics.set(policyName, metrics);
return result;
} catch (e) {
const metrics = policyMetrics.get(policyName) || { calls: 0, totalTime: 0 };
metrics.lastError = e.message;
policyMetrics.set(policyName, metrics);
throw e;
}
};
}
typescript
测试策略建议
describe('函数策略处理器', () => {
const mockContext = { user: { id: 123, roles: ['editor'] } };
it('应正确执行同步函数策略', () => {
const policy = {
type: 2,
effect: 'can',
action: 'publish',
subject: 'Article',
conditions: 'user.roles.includes("editor")',
args: ['user']
};
const ability = handleFunctionType(policy, mockContext);
expect(ability.can('publish', 'Article')).toBe(true);
});
it('应处理异步条件判断', async () => {
const policy = {
type: 2,
effect: 'can',
action: 'delete',
subject: 'Comment',
conditions: `await fetch('/permissions/${user.id}').then(r => r.json())`,
args: ['user']
};
jest.spyOn(global, 'fetch').mockResolvedValue({
json: () => Promise.resolve({ canDelete: true })
});
const ability = await handleAsyncFunctionType(policy, mockContext);
expect(ability.can('delete', 'Comment')).toBe(true);
});
});
typescript
架构示意图
扩展应用场景
1. 跨服务权限委托
async function createDelegatedPolicy(
serviceUrl: string,
localPolicy: IPolicy
) {
const response = await fetch(serviceUrl, {
method: 'POST',
body: JSON.stringify({
action: localPolicy.action,
subject: localPolicy.subject,
context: currentContext
})
});
return {
...localPolicy,
conditions: `(${await response.text()}) === true`
};
}
typescript
2. 时间敏感策略
function createTemporalPolicy(basePolicy: IPolicy, expiry: Date) {
return {
...basePolicy,
conditions: `(new Date() < new Date(${expiry.getTime()})) && (${basePolicy.conditions})`
};
}
typescript
通过以上扩展,函数类型策略可以实现更灵活的动态权限控制,同时保证执行环境的安全性和可观测性。建议根据实际业务场景选择合适的扩展方案。
↑